package com.demo.wrapper.session;

import com.demo.wrapper.session.redis.SessionServiceRedis;
import com.demo.common.utils.CookieUtil;
import com.demo.common.utils.GlobalConstant;
import com.demo.core.SpringContextHolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionContext;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Map;

/** Redis实现分布式session功能的共享
 * http://blog.csdn.net/fengshizty/article/details/50578639
 *
 * 最近项目设计集群，实现了一下session的共享功能，其原理是将session保存到分布式缓存数据库中如：redis， memcache等，然后多个服务器tomcat
 每次请求都通过NoSql数据库查询，如果存在，则获取值；反之存放值。
 我是通过redis来实现session的共享，其主要有一下两种方法：
 1、通过tomcat服务器的拓展功能实现
 这种方式比较简单，主要是通过继承session的ManagerBase类，实现重写session相关的方法，这种比较简单，
 参考源码链接（http://download.csdn.net/detail/fengshizty/9417242）。
 2、通过filter拦截request请求实现
 下面主要介绍这样实现方式：
 （1）写HttpSessionWrapper实现HttpSession接口，实现里面session相关的方法。
 （2）写HttpServletRequestWrapper继承javax.servlet.http.HttpServletRequestWrapper类，重写对于session  相关的方法。
 （3）写SessionFilter拦截配置的请求url，过去cookie中
 的sessionId，如果为空，对此次请求重写生成一个新的sessionId，在sessionId构造新的HttpServletRequestWrapper对象。
 （4）写SessionService实现session到redis的保存和过去，其key为sessionId，value为session对于的Map。
 3、代码实现
 （1）HttpSessionWrapper
 *
 */
//@Component()
//@Scope("prototype")
public class HttpSessionWrapper implements HttpSession {

//    private final static Logger log = Logger.getLogger(HttpSessionWrapper.class);
    private final static Logger log = LoggerFactory.getLogger(HttpSessionWrapper.class);

    private String sid = "";

    private HttpSession session;

    private HttpServletRequest request;

    private HttpServletResponse response;

    private Map<String, Object> map = null;

    private SessionServiceRedis sessionServiceRedis = SpringContextHolder.getBean("sessionServiceRedis");
//    private SessionServiceRedis sessionServiceRedis = null;

//    @Autowired
    /*public HttpSessionWrapper(SessionServiceRedis sessionServiceRedis) {
//        this.sessionServiceRedis = sessionServiceRedis;
        System.out.println("----创建 HttpSessionWrapper 中注入redis服务 ,sessionServiceRedis = "+sessionServiceRedis);
        LOG.info("------创建 HttpSessionWrapper 中注入redis服务 ,sessionServiceRedis = "+sessionServiceRedis);
    }*/

    public HttpSessionWrapper(HttpSession session) {
        this.session = session;
    }

    public HttpSessionWrapper(String sid, HttpSession session) {
        this(session);
        this.sid = sid;
        log.info("----持久化一个session到redis...... sid = "+sid);
        sessionServiceRedis.saveSession(this.sid, this.getSessionMap());
    }

    public HttpSessionWrapper(String sid, HttpSession session,
                              HttpServletRequest request, HttpServletResponse response) {
        this(sid, session);
        this.request = request;
        this.response = response;
//        LOG.info("--------sessionServiceRedis = "+SpringContextHolder.getBean("sessionServiceRedis"));
    }



    //get Map data from redis
    private Map<String, Object> getSessionMap() {
        Assert.notNull(this.sessionServiceRedis ,"sessionServiceRedis 不能为 null ");
        if (this.map == null) {
            this.map = sessionServiceRedis.getSession(this.sid);
        }
        return this.map;
    }

    //get attribute from session of redis
    @Override
    public Object getAttribute(String name) {
        if (this.getSessionMap() != null) {
            Object value = this.getSessionMap().get(name);
            return value;
        }
        return null;
    }

    //save new value to redis
    @Override
    public void setAttribute(String name, Object value) {
        Assert.notNull (this.sessionServiceRedis ,"sessionServiceRedis 不能为 null ");
        this.getSessionMap().put(name, value);
        sessionServiceRedis.saveSession(this.sid, this.getSessionMap());
    }

    //set session invalidate
    @Override
    public void invalidate() {
        Assert.notNull (this.sessionServiceRedis ,"sessionServiceRedis 不能为 null ");
        this.getSessionMap().clear();
        sessionServiceRedis.removeSession(this.sid);//delete from redis
        CookieUtil.removeCookieValue(this.request, this.response, GlobalConstant.JSESSIONID);
    }

    //remove attribute from session
    @Override
    public void removeAttribute(String name) {
        Assert.notNull (this.sessionServiceRedis  ,"sessionServiceRedis 不能为 null ");
        this.getSessionMap().remove(name);
        sessionServiceRedis.saveSession(this.sid, this.getSessionMap());
    }
    @SuppressWarnings("unchecked")
    @Override
    public Object getValue(String name) {
        return this.session.getValue(name);
    }

    @Override
    public Enumeration<String> getAttributeNames() {
        /**
         * 已经过期
         * return (new Enumerator(this.getSessionMap().keySet(), true));
         */
        return Collections.enumeration(this.getSessionMap().keySet());
    }


    @Override
    public String[] getValueNames() {
        return this.session.getValueNames();
    }

    @Override
    public void putValue(String name, Object value) {
        this.session.putValue(name, value);
    }

    @Override
    public void removeValue(String name) {
        this.session.removeValue(name);
    }

    @Override
    public long getCreationTime() {
        return this.session.getCreationTime();
    }

    @Override
    public String getId() {
        return this.sid;
    }

    @Override
    public long getLastAccessedTime() {
        return this.session.getLastAccessedTime();
    }

    @Override
    public ServletContext getServletContext() {
        return this.session.getServletContext();
    }

    @Override
    public void setMaxInactiveInterval(int interval) {
        this.session.setMaxInactiveInterval(interval);
    }

    @Override
    public int getMaxInactiveInterval() {
        return this.session.getMaxInactiveInterval();
    }

    @SuppressWarnings("unchecked")
    @Override
    public HttpSessionContext getSessionContext() {
        return this.session.getSessionContext();
    }

    @Override
    public boolean isNew() {
        return this.session.isNew();
    }
}
